/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved.
 * secGear is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include <stdio.h>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <linux/limits.h>

#include "enclave.h"
#include "kv_u.h"
#include "common.h"

#include <string>
using namespace std;

// #define RSA_PUBLIC_KEY_FILE "pubkey.pem"
clock_t start, stop;                            // 时间参数

cc_enclave_t global_eid = {};                   // 全局enclave_id      
cc_enclave_result_t res = CC_FAIL;              // enclave状态结果
uint8_t buf[VALUE_SIZE] = {0};         // 缓冲区
char temp[VALUE_SIZE + 1];
int retval = 0;
// 创建enclave
int CreateEnclave() 
{
    int  retval = 0;
    const char *path = PATH;


    char real_p[PATH_MAX];
    /* check file exists, if not exist then use absolute path */
    if (realpath(path, real_p) == NULL) {
        if (getcwd(real_p, sizeof(real_p)) == NULL) {
            printf("Cannot find enclave.sign.so");
            return res;
        }
        if (PATH_MAX - strlen(real_p) <= strlen("/enclave.signed.so")) {
            printf("Failed to strcat enclave.sign.so path");
            return res;
        }
        (void)strcat(real_p, "/enclave.signed.so");
    }
    // 创建飞地
    res = cc_enclave_create(
            real_p, 
            AUTO_ENCLAVE_TYPE, 
            0, 
            SECGEAR_DEBUG_FLAG, 
            NULL, 
            0, 
            &global_eid);
    return res;
}
// 销毁enclave
void DestoryEnclave()
{
    res = cc_enclave_destroy(&global_eid);
    if(res != CC_SUCCESS) {
        printf("host destroy enclave error\n");
    } else {
        printf("host destroy enclave success\n");
    }
}
// 打印测试函数（ocall-function）
void print(uint64_t c) {
    std::cout << c << std::endl;
}

// 添加键值对
int Set(int key, char *value_str)
{
    VALUE Value;
    Value.value = new uint8_t[VALUE_SIZE];
    memcpy(Value.value, value_str, strlen(value_str));
    Value.val_len = strlen(value_str);                  // 获取value长度
    uint64_t val_addr = (uint64_t)Value.value;          // 获取value地址

    // 发起ecall插入键值对值
    res = Set_KV(&global_eid,                   // enclave_id 
                    &retval,                    // 返回值
                    key,                        // key
                    val_addr,                   // value地址
                    Value.val_len               // value长度
                    );
    if (res != CC_SUCCESS || retval != 0) {
        std::cout << "Set KV failed!\n";
        return -1;
    }
    return 0;
}
// 获取键值对
int Get(int key)
{
    uint8_t *value_val = new uint8_t[VALUE_SIZE];
    // 发起ecall查询键值对
    res = Get_KV(&global_eid,                   // enclave_id
                    &retval,                    // 返回值
                    key,                        // key
                    value_val                   // value值
                    );
    if (res != CC_SUCCESS || retval != 0) {
        std::cout << "Get KV failed!\n";
        return -1;
    }
    std::cout << key << ": " << value_val << std::endl;
    return 0;
}

int Delete(int key_val)
{   
    // 发起ecall删除键值对
    res = Delete_KV(&global_eid,
                    &retval,
                    key_val);
    if (res != CC_SUCCESS || retval != 0) {
        std::cout << "Delete KV failed!\n";
        return -1;
    }
    return 0;
}

int main()
{
    double set_during, get_during;

    int retval;
    // 创建飞地
    if (CreateEnclave() != 0) {
        std::cout << "Create enclave failed\n";
        return -1;
    }
    start = clock();
    for (int j = 0;j < TEST_ITEM_SIZE;j++) {

        char sv[VALUE_SIZE + 1] = {'\0'};
        for (int i = 0;i < VALUE_SIZE;i++) {
            sv[i] = 'a' + rand()%26;
        }
        // 发起ecall 建立键值对映射信息
        // cout << sv << endl;
        if (Set(j, sv) < 0) {
            cout << j << endl;
            break;
        }
        // Set(j, sv);
    }
    stop = clock();
    set_during = double(stop - start) /CLOCKS_PER_SEC;


    start = clock();
    // 发起ecall 查询键值对信息
    for (int i = 0;i < TEST_ITEM_SIZE;i++) {
        Get(i);

    }
    stop = clock();
    get_during = double(stop- start) / CLOCKS_PER_SEC;
    
    
    cout << "Set消耗时间: " << set_during << 's' << endl;
    cout << "Get消耗时间: " << get_during << 's' << endl;

    // 发起ecall 删除键值对
    
    return res;
}
